#include "USART_SendString.h"

/**
 * @brief  配置 USART1 的 TX（PA9）和 RX（PA10）引脚
 * @param  无
 * @retval 无
 */
void USART1_TxRx_Init(void) {
    // 开启 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 

    // 配置 PA9（USART1 TX）：说明书指定USART1输出引脚
    GPIO_InitTypeDef GPIO_InitStruct;				// 定义结构体
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; 			// 结构体引脚：9
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;    // 结构体模式：【复用】推挽输出模式，需要单片机而非GPIOA模块进行操作
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;   // 结构体速度：引脚输出速度可以选择2MHz,对于串口通信的慢速率来说（115200）,2MHz足矣
    GPIO_Init(GPIOA, &GPIO_InitStruct); 			// 初始化结构体

    // 配置 PA10（USART1 RX）：说明书指定USART1输入引脚
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;  		  	 // 结构体引脚：9
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入模式：适合具有稳定输入的引脚，此处也可替换为上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStruct);  				 // 初始化结构体
}

/**
  * @brief   初始化USAR1外设,数据位是8位,不带校验位,停止位是1位,波特率是115200
  * @param   无
  * @retval  无
  */
void USART1_Init(void) {
    // 1.开启USART1外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // 2.利用USART_Init函数完成USART1外设的初始化
    USART_InitTypeDef USART_InitStruct;												// 定义结构体
    USART_InitStruct.USART_BaudRate = 115200;   									// 波特率设置为115200
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    // 不使用硬件流控
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    // 设置为可收可发模式
    USART_InitStruct.USART_Parity = USART_Parity_No;    			// 不进行数据校验
    USART_InitStruct.USART_StopBits = USART_StopBits_1;     		// 选择1位停止位
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;  	    // 数据位是8位
    USART_Init(USART1, &USART_InitStruct);  					    // 初始化结构体

    // 3.使能开启USART1外设
    USART_Cmd(USART1, ENABLE);					   // 开启USART总开关
}

/**
 * @brief  通过USART1发送1个字节的数据到PC
 * @param  待发送的1个字节数据
 * @retval 无
 */
void USART1_SendByte(uint8_t Byte){
	/*
    if (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == SET){   		// 等待发送寄存器数据发送完毕，即状态更换为SET后退出
		USART_SendData(USART1, Byte);   							// 发送1个字节的数据，由USART自动转换成高低电平输出
	}
	// 注意：这里如果TXE未就绪，数据会被丢弃！
	*/
	
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 	// 等发送缓冲区空
    USART_SendData(USART1, Byte);
}

/**
 * @brief  通过 USART1 发送字符串（以 '\0' 结尾）到PC
 * @param  str  指向字符串的指针
 * @retval 无
 */
void USART1_SendString(const char *str) {
    while (*str) {
        USART1_SendByte((uint8_t)*str++);
    }
    // 等待全部数据发送完毕
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);  
}

/**
 * @brief  通过 USART1 发送格式化字符串（类似 printf）
 * @param  format  格式化字符串
 * @param  ...  可变参数
 * @retval 无
 */
void USART1_printf(const char *format, ...) {
    char buffer[1024];  			// 根据需求调整缓冲区大小
    va_list args;
    
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    USART1_SendString(buffer);  // 调用已有的字符串发送函数
}
